"""Main game module, manages the things that have to happen in the main loop"""
import random, pygame
import resource_manager
from math import *
from vecmath import *
from pygame.locals import *

font = fpscounter = display = None
ships = bullets = particles = effects = stars = None
rwidth = rx = ry = rfact = arrow = 0
cam = dimensions = None
vp = [0, 0]
zoom = 1
next_effects_clear=0
delta = 0
_clearimg = None
_debug = ['']
_debug_changed = 1
         
def init(display_size, display_flags):
    """Basic initialization of the game"""
    global font,fpscounter, display, dimensions, rwidth, rx, ry, rfact, arrow, effects, _clearimg
    font = pygame.font.Font(None, 24)
    fpscounter = font.render('fps', 1, (255, 255, 255))
    
    display = pygame.display.set_mode(display_size, display_flags)
    print '========== INFO: =========='
    print 'Driver: '+pygame.display.get_driver()
    print pygame.display.Info()
    print '==========================='
    dimensions = Rect((0, 0), display_size)
    
    # stuff for the radar to draw
    rwidth = 100
    rx, ry = dimensions.bottomright[0] - rwidth, dimensions.bottomright[1] - rwidth
    rfact = rwidth / (sqrt(dimensions.w**2 + dimensions.h**2) * 3)
    arrow = resource_manager.load_image('arrow_b.png')[0],\
            resource_manager.load_image('arrow_r.png')[0]
    
    # effects layer
    effects = pygame.Surface(display_size, HWSURFACE | SRCALPHA, 32)
    effects = effects.convert_alpha()
    
    # image to clear the screen. is it faster to blit this instead jus fill the display?
    _clearimg = pygame.Surface(display_size, HWSURFACE)
    _clearimg = _clearimg.convert()
    
def update_groups(delta):
    """Called each tick, updates the srpite groups
    Delta is the fraction of a full tick that has elapsed since last update,
    passed to avoid actions ocurring faster than they should if wer are lagging"""
    ships.update(delta)
    particles.update(delta)
    bullets.update(delta)
    cam.update()
    stars.update(cam.speed(), zoom)
    
def redraw():
    """Clears and redraws every element of the game that should be drawn"""
    # drawing the gui took too long to be done every tick
    # TODO more elegant way of doing this
    gui_due=0
    if(pygame.time.get_ticks() > next_effects_clear):
        gui_due = 1
    _clear()
    stars.draw(display)
    ships.draw(display)
    bullets.draw(display)
    particles.draw(display)
    if gui_due:
        # radar
        _draw_radar(effects)
        
        # info
        _draw_gui(effects)
        effects.blit(fpscounter, (0,0))
    
    display.blit(effects, (0, 0)) # draw effects layer
    pygame.display.flip() # paste everything to the screen
    
def _drawstring(surface, string, pos):
    """Draws an string in the given position to the given surface"""
    surface.blit(font.render(string, 1, (255, 255, 255)), pos)

def _clear():
    """Clears the screen and the effects layer if due"""
    global next_effects_clear
    if(pygame.time.get_ticks() > next_effects_clear ):
        effects.fill((0, 0, 0, 0), dimensions) # fill everything back to transparent
        next_effects_clear = pygame.time.get_ticks() + 150 # do it again later
        
    display.blit(_clearimg, (0, 0))
                
def _draw_radar(surface):
    """Polls every ship for its position
    and draws them scaled to some sort of radar"""
    pygame.draw.circle(surface, (0, 255, 255), (rx, ry), rwidth, 2)
    pygame.draw.circle(surface, (0, 255, 255), (rx, ry), rwidth / 1.5, 2)
    pygame.draw.circle(surface, (0, 255, 255), (rx, ry), rwidth / 3, 2)

    ox, oy = cam.position()
    # is faster to use local variables for methods that are used into loops
    b = surface.blit
    s = ships.sprites()
    for sprite in s:
        dx, dy = sprite.position
        d = dist((ox, oy), (dx, dy))
        if d == 0: # is self or over (and you dont need to see this in a radar)
            continue
        
        ang = atan2(dy - oy, dx - ox) # angle the boogie is
        if (d * rfact) > rwidth: # if it's farther the radar can draw it, stick to the border
            x = rx + cos(ang) * rwidth - 5
            y = ry + sin(ang) * rwidth - 5
        else:
            x = rx + cos(ang) * d * rfact - 5 
            y = ry + sin(ang) * d * rfact - 5
        
        if sprite.__module__ == 'vessels.colonial':
            b(arrow[0], (x, y))
        else:
            b(arrow[1], (x, y))
        
def _draw_gui(surface):
    """draws info to the screen"""
    s = cam.speed()
    _drawstring(surface, sqrt(s[0] * s[0] + s[1] * s[1]).__str__(), (400, 40))
    try:
        surface.fill((255, 0, 0), (dimensions.w - 100, 10, cam.sprite.next_sec, 20))
    except:
        pass
    _drawstring(surface, zoom.__str__()+'X', (0, 20))
    _drawstring(surface, len(ships).__str__()+' ships', (0, 40))
    _drawstring(surface, len(bullets).__str__()+' bullets', (0, 60))
    _drawstring(surface, len(particles).__str__()+' particles', (0, 80))
    
    cx = 0
    hd = 20 * len(_debug)
    cy = dimensions.h - hd
    # console
    def dbgstr(str, ypos):
        _drawstring(surface, str, (cx, cy + ypos))
    map(dbgstr, _debug[:len(_debug)], range(0, hd + 1, 20))

def debug(str):
    """Prints to the screen the given string, debug or chat purposes"""
    print str
    _debug.insert(0,pygame.time.get_ticks().__str__() + ': ' + str.__str__())
    if len(_debug) > 5:
        _debug.pop()

class Controller:
    """Base controller class"""
    def __init__(self, ship):
        """ship: the ship to control"""
        self.ship = ship
        self.actions = [0]*6
    def actionmask(self):
        """Converts the boolean action list as a masked long"""
        l = 0
        i = 1
        for e in self.actions:
            if e:
                l |= i
            i <<= 1
        return l
    def onhit(self, by, delta = 1):
        """Respond to fire
        bullet is the bullet that did hit us
        delta is the fraction of a game tick that went last time"""
        pass
    def control(self, delta):
        """Perform actions for this tick, poll for keys, make decisions
        or whathever needs to happen every tick
        
        delta is the fraction of a game tick that went last time"""
        pass